﻿/*********************************************************************************
**                                                                              **
**  Copyright (C) 2024 LiLong                                                   **
**  This file is part of GnssLogs.                                              **
**                                                                              **
**  GnssLogs is free software: you can redistribute it and/or modify            **
**  it under the terms of the GNU Lesser General Public License as published by **
**  the Free Software Foundation, either version 3 of the License, or           **
**  (at your option) any later version.                                         **
**                                                                              **
**  GnssLogs is distributed in the hope that it will be useful,                 **
**  but WITHOUT ANY WARRANTY; without even the implied warranty of              **
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               **
**  GNU Lesser General Public License for more details.                         **
**                                                                              **
**  You should have received a copy of the GNU Lesser General Public License    **
**  along with GnssLogs.  If not, see <https://www.gnu.org/licenses/>.          **
**********************************************************************************/
#pragma once

#include "../ALM.h"
#include "Commons.h"

namespace GnssLogs
{
namespace ALMDecoder
{
using namespace tao::pegtl;
using LogHeader = NMEA_TALKER_IDENTIFIER("ALM");
// clang-format off
struct MsgCount : star<digit> {};
struct MsgID : star<digit> {};
struct PRN : seq<digit, digit> {};
struct GPSWeek : star<digit> {};
struct SVHealth : seq<xdigit, xdigit> {};
struct ECC : rep<4, xdigit> {};
struct AlmRefTime : seq<xdigit, xdigit> {};
struct InclAngle : rep<4, xdigit> {};
struct Omegadot : rep<4, xdigit> {};
struct RtAxis : rep<6, xdigit> {};
struct Omega : rep<6, xdigit> {};
struct LongAscNode : rep<6, xdigit> {};
struct Mo : rep<6, xdigit> {};
struct AF0 : rep<3, xdigit> {};
struct AF1 : rep<3, xdigit> {};
// clang-format on
using Expression = seq<LogHeader,
                       Split,
                       MsgCount,
                       Split,
                       MsgID,
                       Split,
                       PRN,
                       Split,
                       GPSWeek,
                       Split,
                       SVHealth,
                       Split,
                       ECC,
                       Split,
                       AlmRefTime,
                       Split,
                       InclAngle,
                       Split,
                       Omegadot,
                       Split,
                       RtAxis,
                       Split,
                       Omega,
                       Split,
                       LongAscNode,
                       Split,
                       Mo,
                       Split,
                       AF0,
                       Split,
                       AF1,
                       one<'*'>,
                       CheckSum,
                       Tail>;

template<typename T>
struct Action
{
};

template<>
struct Action<LogHeader>
{
    template<typename ParseInput>
    static bool apply(ParseInput& in, ALM::Data& data)
    {
        data.header = std::string(in.begin(), in.size());
        return true;
    }
};

template<>
struct Action<MsgCount> : IntHelper<Action<MsgCount>, uint32_t>
{
    static void setValue(ALM::Data& data, uint32_t value) { data.msgCount = value; }
};

template<>
struct Action<MsgID> : IntHelper<Action<MsgID>, uint32_t>
{
    static void setValue(ALM::Data& data, uint32_t value) { data.msgID = value; }
};

template<>
struct Action<PRN> : IntHelper<Action<PRN>, uint8_t>
{
    static void setValue(ALM::Data& data, uint8_t value) { data.prn = value; }
};

template<>
struct Action<GPSWeek> : IntHelper<Action<GPSWeek>, uint32_t>
{
    static void setValue(ALM::Data& data, uint32_t value) { data.gpsWeek = value; }
};

template<>
struct Action<SVHealth> : IntHelper<Action<SVHealth>, uint8_t, 16>
{
    static void setValue(ALM::Data& data, uint8_t value) { data.svHealth = value; }
};

template<>
struct Action<ECC> : IntHelper<Action<ECC>, uint16_t, 16>
{
    static void setValue(ALM::Data& data, uint16_t value) { data.ecc = value; }
};

template<>
struct Action<AlmRefTime> : IntHelper<Action<AlmRefTime>, uint8_t, 16>
{
    static void setValue(ALM::Data& data, uint8_t value) { data.almRefTime = value; }
};

template<>
struct Action<InclAngle> : IntHelper<Action<InclAngle>, uint16_t, 16>
{
    static void setValue(ALM::Data& data, uint16_t value) { data.inclinationAngle = value; }
};

template<>
struct Action<Omegadot> : IntHelper<Action<Omegadot>, uint16_t, 16>
{
    static void setValue(ALM::Data& data, uint16_t value) { data.omegadot = value; }
};

template<>
struct Action<RtAxis> : IntHelper<Action<RtAxis>, uint32_t, 16>
{
    static void setValue(ALM::Data& data, uint32_t value) { data.rtAxis = value; }
};

template<>
struct Action<Omega> : IntHelper<Action<Omega>, uint32_t, 16>
{
    static void setValue(ALM::Data& data, uint32_t value) { data.omega = value; }
};

template<>
struct Action<LongAscNode> : IntHelper<Action<LongAscNode>, uint32_t, 16>
{
    static void setValue(ALM::Data& data, uint32_t value) { data.longAscNode = value; }
};

template<>
struct Action<Mo> : IntHelper<Action<Mo>, uint32_t, 16>
{
    static void setValue(ALM::Data& data, uint32_t value) { data.mo = value; }
};

template<>
struct Action<AF0> : IntHelper<Action<AF0>, uint16_t, 16>
{
    static void setValue(ALM::Data& data, uint16_t value) { data.af0 = value; }
};

template<>
struct Action<AF1> : IntHelper<Action<AF1>, uint16_t, 16>
{
    static void setValue(ALM::Data& data, uint16_t value) { data.af1 = value; }
};

template<>
struct Action<CheckSum> : CheckSumHelper<Action<CheckSum>>
{
    static void setValue(ALM::Data& data, uint8_t value) { data.checkSum = value; }
};
} // namespace ALMDecoder
} // namespace GnssLogs